﻿using Core.Interface;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace ModBus.Mode
{
    public class ModBusTCP : ModBusDevice
    {
        private IPEndPoint iPEndPoint;
        public IPEndPoint IPEndPoint
        {
            get { return iPEndPoint; }
            set { iPEndPoint = value; }
        }

        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        private TcpClient m_Client;

        private List<byte> m_SendBuffer = new List<byte>();

        private byte[] m_RecvBuffer;

        private readonly object rwLock = new object();

        private NetworkStream Stream;

        public ModBusTCP(string name)
        {
            Name= name;         
        }

        public async Task<bool> ConnectAsync()
        {
            try
            {
                await m_Client.ConnectAsync(IPEndPoint.Address, IPEndPoint.Port);
                m_Client.ReceiveTimeout = 4000;
                m_Client.SendTimeout = 4000;
                Stream = m_Client.GetStream();
                return true;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
        }

        public override bool Connect()
        {
            try
            {
                //在界面上断开再重新连接需要new TcpClient()
                m_Client = new TcpClient();
                m_Client.Connect(IPEndPoint);
                m_Client.ReceiveTimeout = 4000;
                m_Client.SendTimeout = 4000;
                Stream = m_Client.GetStream();
                return true;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
        }

        public override void Close()
        {
            try
            {
                m_Client?.Close();
                Stream?.Close();
                m_RecvBuffer = null;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
        }

        public override bool ReadBit(ushort startAddress, ushort size, out bool[] values)
        {
            lock (rwLock)
            {
                try
                {
                    bool result = false;
                    values = new bool[size];
                    m_SendBuffer?.Clear();
                    m_SendBuffer.Add(0x00);//事务协议
                    m_SendBuffer.Add(0x00);//事务协议
                    m_SendBuffer.Add(0x00);//事务协议
                    m_SendBuffer.Add(0x00);//事务协议

                    m_SendBuffer.Add(0x00);//长度6个字节
                    m_SendBuffer.Add(0x06);//长度6个字节

                    m_SendBuffer.Add(0x01);//单元标识
                    m_SendBuffer.Add(0x01);//功能码

                    byte[] addressBytes = BitConverter.GetBytes(startAddress);
                    Array.Reverse(addressBytes);
                    m_SendBuffer.AddRange(addressBytes);

                    byte[] sizeBytes = BitConverter.GetBytes(size);
                    Array.Reverse(sizeBytes);
                    m_SendBuffer.AddRange(sizeBytes);

                    var tempSize = Math.Ceiling((double)size / 8);
                    m_RecvBuffer = new byte[9 + (int)tempSize];

                    Stream.Write(m_SendBuffer.ToArray(), 0, m_SendBuffer.Count);
                    Stream.Flush();

                    if (Stream.CanRead)
                    {
                        do
                        {
                            int length = Stream.Read(m_RecvBuffer, 0, m_RecvBuffer.Length);
                        } while (Stream.DataAvailable);
                    }

                    if (Check(0x01, 0x01))
                    {
                        byte[] bytes = new byte[(int)tempSize];
                        for (int i = 0; i < tempSize; i++)
                        {
                            bytes[i] = m_RecvBuffer[9 + i];
                        }

                        BitArray bitSet = new BitArray(bytes);
                        var tempBools = new bool[bitSet.Count];
                        bitSet.CopyTo(tempBools, 0);
                        Array.Copy(tempBools, values, size);
                        result = true;
                    }
                    return result;
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message, ex);
                }
            }
        }

        public override bool ReadRegister(ushort startAddress, ushort size, out ushort[] values)
        {
            lock (rwLock)
            {
                try
                {
                    bool result = false;
                    values = new ushort[size];
                    m_SendBuffer?.Clear();
                    m_SendBuffer.Add(0x00);//事务协议
                    m_SendBuffer.Add(0x00);//事务协议
                    m_SendBuffer.Add(0x00);//事务协议
                    m_SendBuffer.Add(0x00);//事务协议

                    m_SendBuffer.Add(0x00);//长度6个字节
                    m_SendBuffer.Add(0x06);//长度6个字节

                    m_SendBuffer.Add(0x01);//单元标识
                    m_SendBuffer.Add(0x03);//功能码

                    byte[] addressBytes = BitConverter.GetBytes(startAddress);
                    Array.Reverse(addressBytes);
                    m_SendBuffer.AddRange(addressBytes);

                    byte[] sizeBytes = BitConverter.GetBytes(size);
                    Array.Reverse(sizeBytes);
                    m_SendBuffer.AddRange(sizeBytes);

                    Stream.Write(m_SendBuffer.ToArray(), 0, m_SendBuffer.Count);
                    Stream.Flush();
                    m_RecvBuffer = new byte[9 + size * 2];
                    if (Stream.CanRead)
                    {
                        do
                        {
                            int length = Stream.Read(m_RecvBuffer, 0, m_RecvBuffer.Length);
                        } while (Stream.DataAvailable);
                    }

                    if (Check(0x01, 0x03))
                    {
                        byte[] mRecv = new byte[2 * size];
                        for (int i = 0; i < size; i++)
                        {
                            mRecv[i * 2] = m_RecvBuffer[9 + i * 2 + 1];
                            mRecv[i * 2 + 1] = m_RecvBuffer[9 + i * 2];
                        }

                        for (int i = 0; i < size; i++)
                        {
                            values[i] = BitConverter.ToUInt16(mRecv, i * 2);
                        }
                        result = true;
                    }
                    return result;

                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message, ex);
                    //工作流记录异常,并赋初值
                }
            }
        }

        public override bool WriteBit(ushort startAddress, ushort size, bool[] values)
        {
            lock (rwLock)
            {
                try
                {
                    bool result = false;
                    m_SendBuffer?.Clear();
                    m_SendBuffer.Add(0x00);//事务协议
                    m_SendBuffer.Add(0x00);//事务协议
                    m_SendBuffer.Add(0x00);//事务协议
                    m_SendBuffer.Add(0x00);//事务协议

                    var tempSize = Math.Ceiling((double)size / 8);
                    byte[] LenBytes = BitConverter.GetBytes((ushort)(7 + tempSize));
                    Array.Reverse(LenBytes);
                    m_SendBuffer.AddRange(LenBytes);//长度

                    m_SendBuffer.Add(0x01);//单元标识

                    m_SendBuffer.Add(0x0F);//功能码

                    byte[] addressBytes = BitConverter.GetBytes(startAddress);
                    Array.Reverse(addressBytes);
                    m_SendBuffer.AddRange(addressBytes);//起始

                    byte[] sizeBytes = BitConverter.GetBytes(size);
                    Array.Reverse(sizeBytes);
                    m_SendBuffer.AddRange(sizeBytes);//数量

                    m_SendBuffer.Add((byte)(tempSize));//字节数

                    var bA = new BitArray(values);
                    byte[] bytes = new byte[(int)tempSize];
                    bA.CopyTo(bytes, 0);
                    m_SendBuffer.AddRange(bytes);//数据

                    Stream.Write(m_SendBuffer.ToArray(), 0, m_SendBuffer.Count);
                    Stream.Flush();

                    m_RecvBuffer = new byte[12];
                    if (Stream.CanRead)
                    {
                        do
                        {
                            int length = Stream.Read(m_RecvBuffer, 0, m_RecvBuffer.Length);
                        } while (Stream.DataAvailable);
                    }

                    result = Check(0x01, 0x0F);
                    return result;
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message, ex);
                }
            }
        }

        public override bool WriteRegister(ushort startAddress, ushort size, ushort[] values)
        {
            lock (rwLock)
            {
                try
                {
                    bool result = false;
                    m_SendBuffer?.Clear();
                    m_SendBuffer.Add(0x00);//事务协议
                    m_SendBuffer.Add(0x00);//事务协议
                    m_SendBuffer.Add(0x00);//事务协议
                    m_SendBuffer.Add(0x00);//事务协议

                    byte[] LenBytes = BitConverter.GetBytes((ushort)(7 + size * 2));
                    Array.Reverse(LenBytes);
                    m_SendBuffer.AddRange(LenBytes);//长度

                    m_SendBuffer.Add(0x01);//单元标识
                    m_SendBuffer.Add(0x10);//功能码

                    byte[] addressBytes = BitConverter.GetBytes(startAddress);
                    Array.Reverse(addressBytes);
                    m_SendBuffer.AddRange(addressBytes);

                    byte[] sizeBytes = BitConverter.GetBytes(size);
                    Array.Reverse(sizeBytes);
                    m_SendBuffer.AddRange(sizeBytes);//数量高低位

                    m_SendBuffer.Add((byte)(2 * size));//字节数

                    foreach (var value in values)
                    {
                        byte[] writebytes = BitConverter.GetBytes(value);
                        Array.Reverse(writebytes);
                        m_SendBuffer.AddRange(writebytes);
                    }

                    Stream.Write(m_SendBuffer.ToArray(), 0, m_SendBuffer.Count);
                    Stream.Flush();
                    m_RecvBuffer = new byte[12];
                    if (Stream.CanRead)
                    {
                        do
                        {
                            int length = Stream.Read(m_RecvBuffer, 0, m_RecvBuffer.Length);
                        } while (Stream.DataAvailable);
                    }

                    result = Check(0x01, 0x10);
                    return result;
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message, ex);
                }
            }
        }

        private bool Check(byte add, byte funCode)
        {
            try
            {
                return (add == m_RecvBuffer[6]) && (funCode == m_RecvBuffer[7]);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
        }
    }
}
